#!/usr/bin/with-contenv bashio
# vim: ft=bash
# shellcheck shell=bash
# ==============================================================================
# OpenThread BorderRouter start script
# ==============================================================================

# shellcheck disable=SC1091
. /etc/s6-overlay/scripts/otbr-agent-common

declare backbone_if
declare device
declare baudrate
declare flow_control
declare otbr_log_level
declare otbr_log_level_int
declare otbr_rest_listen
declare otbr_rest_listen_port

backbone_if="$(bashio::api.supervisor 'GET' '/network/info' '' 'first(.interfaces[] | select (.primary == true)) .interface')"
device=$(bashio::config 'device')

if bashio::config.has_value 'network_device'; then
    device="/tmp/ttyOTBR"
fi

baudrate=$(bashio::config 'baudrate')
flow_control=""

if bashio::config.true 'flow_control'; then
    flow_control="&uart-flow-control"
else
    flow_control="&uart-init-deassert"
fi

otbr_log_level=$(bashio::string.lower "$(bashio::config otbr_log_level)")
case "${otbr_log_level}" in
    debug)
        otbr_log_level_int="7"
        ;;
    info)
        otbr_log_level_int="6"
        ;;
    notice)
        otbr_log_level_int="5"
        ;;
    warning)
        otbr_log_level_int="4"
        ;;
    error)
        otbr_log_level_int="3"
        ;;
    critical)
        otbr_log_level_int="2"
        ;;
    alert)
        otbr_log_level_int="1"
        ;;
    emergency)
        otbr_log_level_int="0"
        ;;
    *)
        bashio::exit.nok "Unknown otbr_log_level: ${otbr_log_level}"
        ;;
esac

# shellcheck disable=SC2086
if [ -z ${backbone_if} ]; then
    bashio::log.warning "No primary network interface found! Using static eth0."
    backbone_if="eth0"
fi

# shellcheck disable=SC2015
mkdir -p /data/thread && ln -sft /var/lib /data/thread || bashio::exit.nok "Could not create directory /var/lib/thread to store Thread data."

# We compile the OTBR with firewall support, so otbr-agent tries to update the
# ipsets. Therefor, create ipsets always to avoid errors from otbr-agent. Just
# the ipsets  won't have an effect in practice when the firewall is disabled.
ipset create -exist otbr-ingress-deny-src hash:net family inet6
ipset create -exist otbr-ingress-deny-src-swap hash:net family inet6
ipset create -exist otbr-ingress-allow-dst hash:net family inet6
ipset create -exist otbr-ingress-allow-dst-swap hash:net family inet6

if bashio::config.true 'firewall'; then
    bashio::log.info "Setup OTBR firewall..."
# shellcheck disable=SC2086,SC2154
    ip6tables -N $otbr_forward_ingress_chain
# shellcheck disable=SC2086,SC2154
    ip6tables -I FORWARD 1 -o $thread_if -j $otbr_forward_ingress_chain

    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_ingress_chain -m pkttype --pkt-type unicast -i ${thread_if} -j DROP
    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_ingress_chain -m set --match-set otbr-ingress-deny-src src -j DROP
    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_ingress_chain -m set --match-set otbr-ingress-allow-dst dst -j ACCEPT
    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_ingress_chain -m pkttype --pkt-type unicast -j DROP
    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_ingress_chain -j ACCEPT

    # shellcheck disable=SC2086,SC2154
    ip6tables -N $otbr_forward_egress_chain
    # shellcheck disable=SC2086
    ip6tables -I FORWARD 2 -i $thread_if -j $otbr_forward_egress_chain
    # shellcheck disable=SC2086
    ip6tables -A $otbr_forward_egress_chain -j ACCEPT
else
    # Make sure ip6tables (as used by Docker) allow IP forwarding
    ip6tables -P FORWARD ACCEPT
    # HAOS 9.3 and earlier (for 9.4 accept is the default so this won't do anything)
    ip6tables-legacy -P FORWARD ACCEPT
fi

if bashio::config.true 'nat64'; then
    # shellcheck disable=SC2086
    iptables -t mangle -A PREROUTING -i ${thread_if} -j MARK --set-mark 0x1001
    iptables -t nat -A POSTROUTING -m mark --mark 0x1001 -j MASQUERADE
    # shellcheck disable=SC2086
    iptables -t filter -A FORWARD -o ${backbone_if} -j ACCEPT
    # shellcheck disable=SC2086
    iptables -t filter -A FORWARD -i ${backbone_if} -j ACCEPT
fi

otbr_rest_listen="::"
otbr_rest_listen_port="$(bashio::addon.port 8081)"

# If user port is not set, listen on local interface only
if ! bashio::var.has_value "${otbr_rest_listen_port}"; then
    otbr_rest_listen="$(bashio::addon.ip_address)"
    otbr_rest_listen_port="8081"
elif [ "${otbr_rest_listen_port}" != "8081" ]; then
    bashio::log.warning "Custom OpenThread REST API port is not supported. Using 8081."
    otbr_rest_listen_port="8081"
fi

# Store REST API listen information for check script
echo "${otbr_rest_listen}" > /tmp/otbr-agent-rest-api
echo "${otbr_rest_listen_port}" >> /tmp/otbr-agent-rest-api

bashio::log.info "Starting otbr-agent..."
# shellcheck disable=SC2086
exec s6-notifyoncheck -d -s 300 -w 300 -n 0 stdbuf -oL \
    "/usr/sbin/otbr-agent" -I ${thread_if} -B "${backbone_if}" \
        --rest-listen-address "${otbr_rest_listen}" \
        -d${otbr_log_level_int} -v -s \
        "spinel+hdlc+uart://${device}?uart-baudrate=${baudrate}${flow_control}" \
        "trel://${backbone_if}"
